/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include "buffer.h"
/* typedef -------------------------------------------------------------------*/
/* define --------------------------------------------------------------------*/
/* macro ---------------------------------------------------------------------*/
/* variables -----------------------------------------------------------------*/
/* function prototypes -------------------------------------------------------*/
/* functions -----------------------------------------------------------------*/
/*******************************************************************************************

  * @brief  LoopBuffer_Init
  * @param  loopBuffer: loop buffer object
            buffer: buffer pointer
            bufferSize: count of member
  * @retval 0, successfully
  * @remark 

********************************************************************************************/
void LoopBuffer_Init(struct LoopBuffer *loopBuffer, void *buffer, size_t bufferSize)
{
    memset(loopBuffer, 0, sizeof(struct LoopBuffer));
    loopBuffer->buffer = buffer;
    loopBuffer->bufferLength = bufferSize;
}
/*******************************************************************************************

  * @brief  LoopBuffer_Fill
  * @param  loopBuffer, loop buffer object
            data, the pointer of data which add into loop buffer
            size, the byte count of data
  * @retval 
  * @remark 

********************************************************************************************/
void LoopBuffer_Fill(struct LoopBuffer *loopBuffer, void *data, size_t size)
{
    int countRemain = loopBuffer->bufferLength - loopBuffer->_pointer;

    if(countRemain >= size)
    {
        memcpy(loopBuffer->buffer + loopBuffer->_pointer, data, size);
        loopBuffer->_pointer += size;
        if(loopBuffer->_pointer == loopBuffer->bufferLength)
        {   
            loopBuffer->_pointer = 0;
            loopBuffer->_flag |= LOOP_BUFFER_FULL;
        }
    }
    else
    {
        memcpy(loopBuffer->buffer + loopBuffer->_pointer, data, countRemain);
        memcpy(loopBuffer->buffer, (uint8_t *)data + countRemain, size - countRemain);
        loopBuffer->_pointer = size - countRemain;
        loopBuffer->_flag |= LOOP_BUFFER_FULL;
    }
}
/*******************************************************************************************

  * @brief  LoopBuffer_IsFull
  * @param  loopBuffer, loop buffer object
  * @retval 
  * @remark 

********************************************************************************************/
__inline bool LoopBuffer_IsFull(struct LoopBuffer *loopBuffer)
{
    return ((loopBuffer->_flag & LOOP_BUFFER_FULL) != 0);
}
/*******************************************************************************************

  * @brief  LoopBuffer_Interate
  * @param  loopBuffer, loop buffer object
  *         size, the size of element
  *         param, handler param
  *         handler, the handler of each member
  * @retval -1
  * @remark 

********************************************************************************************/
int LoopBuffer_Interate(struct LoopBuffer *loopBuffer, int step, void *param, void (*handler)(void *data, int index, void *param))
{
    int i=0, j=0;

    /* check if the step is legal */
    if(LoopBuffer_IsFull(loopBuffer) == false)
    {
        if((loopBuffer->_pointer % step) != 0)
        {   return -1;  }
    }
    else
    {
        if((loopBuffer->bufferLength % step) != 0)
        {   return -1;  }
    }

    /* interate to handler data */
    if(LoopBuffer_IsFull(loopBuffer) == false)
    {
        for(i=0; i<(loopBuffer->_pointer/step); i++)
        {   handler(loopBuffer->buffer + i*step, i, param);    }        
    }
    else
    {
        for(i=0; i<((loopBuffer->bufferLength - loopBuffer->_pointer)/step); i++)
        {   handler(loopBuffer->buffer + loopBuffer->_pointer + i*step, i, param);    }   

        for(j=0; j<(loopBuffer->_pointer/step); j++)
        {   handler(loopBuffer->buffer + j*step, i+j, param);    } 
    }

    return 0;
}
/*******************************************************************************************

  * @brief  LoopBuffer_Clip
  * @param  loopBuffer: loop buffer object
            remainCount: the byte count of remain
  * @retval 0, successfully
            -105 ENOBUFS, no space to alloc to put packet
  * @remark clip period from loop buffer and occur new event

********************************************************************************************/
int LoopBuffer_Clip(struct LoopBuffer *loopBuffer, size_t remainCount)
{
    loopBuffer->_end = loopBuffer->bufferLength - remainCount;            
    uint8_t *blank = NULL;
    int result = 0;
    size_t size = 0;
    
    /* if header is not over the end of array */
    if (loopBuffer->_end > loopBuffer->_start)
    {   
        size = loopBuffer->_end - loopBuffer->_start  + 1;      // additional byte is use for string end '\0'
        blank = malloc(size);
        if(blank != NULL)
        {   
            memset(blank, 0, size); 
            memcpy(blank, loopBuffer->buffer + loopBuffer->_start, loopBuffer->_end - loopBuffer->_start);
            
            if(loopBuffer->event.new != NULL)
            {   loopBuffer->event.new(blank, size); }
        }
        else
        {   
            result = -105;      // ENOBUFS  
            goto __end;
        }
    }
    /* if the header is over the end of array */
    else if (loopBuffer->_end < loopBuffer->_start)
    {
        size = loopBuffer->bufferLength - loopBuffer->_start + loopBuffer->_end + 1;
        blank = malloc(size);
        
        if(blank != NULL)
        {
            memset(blank, 0, size);
            memcpy(blank,
                   loopBuffer->buffer + loopBuffer->_start,
                   loopBuffer->bufferLength - loopBuffer->_start);

            memcpy(blank + loopBuffer->bufferLength - loopBuffer->_start,
                   loopBuffer->buffer,
                   loopBuffer->_end + 1);
            
            if(loopBuffer->event.new != NULL)
            {   loopBuffer->event.new(blank, size); }
            
        }
        else
        {   
            result = -105;          // ENOBUFS
            goto __end;
        }
    }
__end:
    loopBuffer->_start = loopBuffer->_end;
    return result;
}
/*******************************************************************************************

  * @brief  LoopBuffer_RegisterEventNew
  * @param  loopBuffer: loop buffer object
            handler: the handler function of specified event
  * @retval 
  * @remark 

********************************************************************************************/
inline void LoopBuffer_RegisterEventNew(struct LoopBuffer *loopBuffer, void (*new)(uint8_t *packet, size_t len))
{
    loopBuffer->event.new = new;
}